//Comment
import java.net.URL;
import java.util.Vector;
import java.util.HashMap;
import java.util.Arrays;
import com.vmware.vim25.*;
import com.vmware.vim25.mo.*;
import java.io.*;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;

public class controller {
	public static void main(String[] args) throws Exception
	{

		BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
		ServiceInstance si = new ServiceInstance(new URL("https://192.168.0.43/sdk"), "Administrator", "Habloo12", true);
		Folder rootFolder = si.getRootFolder();
		String sourcename = "minicentos";
		String targetname = sourcename + "-clone";
		int Player1NextNum = 1;
		int Player2NextNum = 1;
		int gametime = 20;
		Vector Player1VMs = new Vector();
		Vector Player2VMs = new Vector();

		VirtualMachine sourcevm = (VirtualMachine) new InventoryNavigator(rootFolder).searchManagedEntity("VirtualMachine",sourcename);
		//Now remove all of its snaps & clones (just to be sure)
		resetBaseVM(si, rootFolder, sourcevm);		
		//Now create a new snap
		createBaseSnapshot(sourcevm);

		allTasksDone(si); //Wait for tasks to finish
		System.out.println("Game Start!");
		long startTime = System.currentTimeMillis()/1000;
		long endTime = startTime + gametime; //N second game time.
		while(true){
			
			if (System.currentTimeMillis()/1000 > endTime) {
				break;
			} else {
				long timeLeft = endTime - System.currentTimeMillis()/1000;
				System.out.println(timeLeft +" seconds Remaining...");
				
			}
			
			
			Player1VMs = getVMsForPlayer(rootFolder,1);
			Player2VMs = getVMsForPlayer(rootFolder,2);		
			
			int player1Count = 0;
			int player2Count = 0;
			
			if (buffer.ready()) {
				try {
					player1Count = Integer.parseInt(buffer.readLine());
					player2Count = Integer.parseInt(buffer.readLine());
				}
				catch (Exception e) {
				
				}
			}
			
			
			
			if (player1Count == 9) {
				System.out.println("Deleting a VM from Player 2...MWAHAHAHAHA");
				destroyOpponentVM(rootFolder,Player2VMs);
			}
			if (player2Count == 9) {
				System.out.println("Deleting a VM from Player 1...MWAHAHAHAHA");
				destroyOpponentVM(rootFolder,Player1VMs);
			}
			if (player1Count > 0 && player1Count < 9 ) {
				for (int i = 0; i < player1Count; i++) {
					Task t = createLinkedClone(si,sourcevm,"Player1",Player1NextNum++);

				}
			} 
			if (player2Count > 0 && player2Count < 9 ) {
				for (int i = 0; i < player2Count; i++) {
					Task t = createLinkedClone(si,sourcevm,"Player2",Player2NextNum++);

				}
			} 
			Thread.sleep(1000);
		}

		System.out.println("Game Over!");

		allTasksDone(si); //Wait for tasks to finish
		Player1VMs = getVMsForPlayer(rootFolder,1);
		Player2VMs = getVMsForPlayer(rootFolder,2);
		
		HashMap player1Totals = calcTotals(Player1VMs);
		HashMap player2Totals = calcTotals(Player2VMs);

		System.out.println("Final Tallies!");
		System.out.println("Player 1: " + player1Totals.get("CPU") + " CPUs" );
		System.out.println("Player 1: " + player1Totals.get("MEM") + " MB " );
		System.out.println("Player 1: " + player1Totals.get("CNT") + " VMs " );
		
		System.out.println("Player 2: " + player2Totals.get("CPU") + " CPUs" );
		System.out.println("Player 2: " + player2Totals.get("MEM") + " MB " );
		System.out.println("Player 2: " + player2Totals.get("CNT") + " VMs " );		
		
		System.out.print("Winner: ");
		if ( ((Integer) player1Totals.get("CNT")).intValue() == ((Integer) player2Totals.get("CNT")).intValue() ){
			System.out.println("TIE!!!");
		} else if (  ((Integer) player1Totals.get("CNT")).intValue() < ((Integer) player2Totals.get("CNT")).intValue()  ) {
			System.out.println("Player 2!");
		} else {
			System.out.println("Player 1!");
		}

		System.out.println("Cleaning Up After Myself");
		allTasksDone(si); //Wait for tasks to finish
		resetBaseVM(si, rootFolder, sourcevm);
		
		si.getServerConnection().logout();
	}
	
	static void allTasksDone(ServiceInstance si) throws Exception {
		System.out.println("Waiting for all Tasks to finish");
		while (numOutstandingTasks(si) > 0) {
			//System.out.println(numOutstandingTasks(si) + " ...");
			Thread.sleep(5000);
		}
	}

	static HashMap calcTotals(Vector playerVMs) {
		HashMap m = new HashMap();
		int totalCPUs = 0;
		int totalMem = 0;
		int count = 0;
		for (Object v : playerVMs) {
			VirtualMachine vm = (VirtualMachine) v;
			totalCPUs = totalCPUs + vm.getSummary().getConfig().numCpu;
			totalMem = totalMem + vm.getSummary().getConfig().memorySizeMB;
			count++;
		}
		m.put("CPU",new Integer(totalCPUs));
		m.put("MEM",new Integer(totalMem));
		m.put("CNT",new Integer(count));
		return m;
	}

	static void createBaseSnapshot(VirtualMachine vm) throws Exception {
		Task task = vm.createSnapshot_Task("base-snap", "Base Snapshot for Linked Clones", false, true);
		if(task.waitForMe()== Task.SUCCESS) {
			System.out.println("Created base snapshot for base VM: " + vm.getName());
		}
	}
	
	static void resetBaseVM(ServiceInstance si, Folder rootFolder, VirtualMachine vm) throws Exception {
		destroyClones(si, rootFolder, vm.getName());
		removeAllSnaps(vm);
		Thread.sleep(1000);
		allTasksDone(si); //Wait for tasks to finish
	}

	static void removeAllSnaps(VirtualMachine vm) throws Exception {
		Task task = vm.removeAllSnapshots_Task();      
		if(task.waitForMe()== Task.SUCCESS) {
			System.out.println("Removed all snapshots for base VM: " + vm.getName());
		}
	}

	static void destroyOpponentVM(Folder rootFolder, Vector playerVMs) throws Exception {
		if (!playerVMs.isEmpty()) {
			VirtualMachine vm = (VirtualMachine) playerVMs.firstElement();
			try {
				Task task = vm.powerOffVM_Task();
				String ret = task.waitForMe();
				Task t = vm.destroy_Task();
			}
			catch (com.vmware.vim25.InvalidPowerState e) {
				
			}
		}
	}

	static void destroyClones(ServiceInstance si, Folder rootFolder, String basename) throws Exception {
		System.out.println("Removing VMs from previous games...");
		ManagedEntity[] vms = new InventoryNavigator(rootFolder).searchManagedEntities(new String[][] { {"VirtualMachine", "name" }, }, true);
		for(int i=0; i<vms.length; i++)
		{
			if (vms[i].getName().startsWith("Player")) {
				System.out.println("Found / Removing VM: "+vms[i].getName());
				VirtualMachine vm = (VirtualMachine) new InventoryNavigator(rootFolder).searchManagedEntity("VirtualMachine",vms[i].getName());
				try {
					String[] disabledMethods = vm.getDisabledMethod();
					Arrays.sort(disabledMethods);
					if (Arrays.binarySearch(disabledMethods,"PowerOffVM_Task") < 0) {
						Task task = vm.powerOffVM_Task();
						String ret = task.waitForMe();
					}
				} catch (InvalidPowerState e) {}
				Task t = vm.destroy_Task();
				//String retval = t.waitForMe();
				//System.out.println(retval);
			}
		}
		allTasksDone(si);//Wait for tasks to finish
	}
	
	static Vector getVMsForPlayer(Folder rootFolder, int playerNum) throws Exception {
		Vector v = new Vector();
		//System.out.println("Finding VMs for Player " + playerNum);
		ManagedEntity[] vms = new InventoryNavigator(rootFolder).searchManagedEntities(new String[][] { {"VirtualMachine", "name" }, }, true);
		for(int i=0; i<vms.length; i++)
		{
			if (vms[i].getName().startsWith("Player"+playerNum)) {
				//System.out.print("Found VM: "+vms[i].getName()+": ");
				VirtualMachine vm = (VirtualMachine) new InventoryNavigator(rootFolder).searchManagedEntity("VirtualMachine",vms[i].getName());
				v.addElement(vm);
			}
		}
		return v;
	}
	
	static Task createLinkedClone(ServiceInstance si, VirtualMachine sourcevm, String targetName, int index) throws Exception {
		
		//When you clone a VM, you have to specify a whole bunch of stuff about where to put it, how to configure it, etc.
		//First we create the cloneSpec object:
		VirtualMachineCloneSpec cloneSpec = new VirtualMachineCloneSpec();
		cloneSpec.setPowerOn(false); //Poweron after cloning?
		cloneSpec.setTemplate(false); //Is this a template?
		cloneSpec.setSnapshot(sourcevm.getSnapshot().getCurrentSnapshot());
		
		VirtualMachineRelocateSpec reloc = new VirtualMachineRelocateSpec();
		reloc.setDiskMoveType(VirtualMachineRelocateDiskMoveOptions.createNewChildDiskBacking.toString());
		
		
		cloneSpec.setLocation(reloc);
		System.out.println("Initiating clone VM " +targetName+"-"+index+" from VM "+sourcevm.getName());
		Task cloneTask = sourcevm.cloneVM_Task((Folder) sourcevm.getParent(),targetName+"-"+index,cloneSpec);
		//String status = cloneTask.waitForMe();

		return cloneTask;
	}
  
    static TaskFilterSpec createTaskFilterSpec(ManagedEntity ent) {
    TaskFilterSpec tfs = new TaskFilterSpec();
    // only the root initiated tasks
    TaskFilterSpecByUsername nameFilter 
      = new TaskFilterSpecByUsername();
    nameFilter.setUserList(new String[] {"Administrator"});
    // include tasks initiated by non-users, 
    // for example, by ScheduledTaskManager.
    nameFilter.setSystemUser(true);
    tfs.setUserName(nameFilter);
    // only the tasks with one entity itself
    TaskFilterSpecByEntity entFilter = 
      new TaskFilterSpecByEntity();
    entFilter.setEntity(ent.getMOR());
    entFilter.setRecursion(TaskFilterSpecRecursionOption.all);
    tfs.setEntity(entFilter);
    // only in progress tasks
    tfs.setState(new TaskInfoState[]{TaskInfoState.queued, TaskInfoState.running});
    // only tasks started within last one month
    // strictly speaking, time should be retrieved from server
    TaskFilterSpecByTime tFilter =new TaskFilterSpecByTime();
    Calendar cal = Calendar.getInstance();
    cal.roll(Calendar.DATE, -1);
    tFilter.setBeginTime(cal); 
    //we ignore the end time here so it gets the latest.
    tFilter.setTimeType(TaskFilterSpecTimeOption.startedTime);
    tfs.setTime(tFilter);
    // Optionally, you limits tasks initiated by scheduled task
    // with the setScheduledTask() method. 
    return tfs;
  }

	static int numOutstandingTasks(ServiceInstance si) throws Exception {
		TaskManager taskMgr = si.getTaskManager();
		if(taskMgr!=null)
		{
			Folder root = si.getRootFolder();
			TaskFilterSpec tfs = createTaskFilterSpec(root); 
			TaskHistoryCollector thc = taskMgr.createCollectorForTasks(tfs);
			// Note: 10 <= pagesize <= 62
			thc.setCollectorPageSize(62);
			TaskInfo[] tis = thc.getLatestPage();
			
			//System.out.println(tis);
			tis= thc.readNextTasks(100);
			//System.out.println(tis);
			int total = 0;
			if (tis == null) {total = 0;}
			else {total = tis.length;}
			//System.out.println(total + " tasks left");
			return total;
		}
		throw new Exception("Gack - Didn't get the Task History Collector");

	}
}
